package lol.clann.bukkit.pluginboot.model.gui;

import lol.clann.clannboot.annotation.svc.Service;
import org.bukkit.command.CommandException;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.HumanEntity;
import org.bukkit.event.Event;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.*;
import org.bukkit.inventory.Inventory;

import javax.annotation.Nonnull;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * @author pyz
 * @date 2018/8/12 下午3:08
 */
@Service(priority = Integer.MAX_VALUE)
public class InventoryListener implements Listener {

    private Map<Integer, InventoryWrapper> wrappers = new HashMap<>();
    private Map<Inventory, InventoryWrapper> inventories = new HashMap<>();

    @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
    public void event(InventoryOpenEvent event) {
        call(event, event.getPlayer(), event::getInventory, InventoryWrapper::getOpen);
    }

    @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
    public void event(InventoryCloseEvent event) {
        call(event, event.getPlayer(), event::getInventory, InventoryWrapper::getClose);
    }

    @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
    public void event(InventoryClickEvent event) {
        call(event, event.getWhoClicked(), event::getInventory, InventoryWrapper::getClick);
    }

    @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
    public void event(InventoryCreativeEvent event) {
        call(event, event.getWhoClicked(), event::getInventory, InventoryWrapper::getCreative);
    }

    @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
    public void event(InventoryDragEvent event) {
        call(event, event.getWhoClicked(), event::getInventory, wrapper -> wrapper.getDrag());
    }

    @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
    public void event(InventoryPickupItemEvent event) {
        call(event, null, event::getInventory, InventoryWrapper::getPickupItem);
    }

    private <T extends Event> void call(T event, HumanEntity human, Supplier<Inventory> inventoryGetter, Function<InventoryWrapper, Consumer<T>> function) {
        try {
            Inventory inventory = inventoryGetter.get();
            InventoryWrapper wrapper = inventories.get(inventory);
            if (wrapper == null) {
                return;
            }
            Consumer<T> click = function.apply(wrapper);
            if (click == null) {
                return;
            }
            click.accept(event);
        } catch (CommandException e) {
            if (human instanceof CommandSender) {
                ((CommandSender) human).sendMessage(e.getMessage());
            } else {
                throw e;
            }
        }
    }

    public void register(int id, @Nonnull InventoryWrapper wrapper) {
        InventoryWrapper previous = wrappers.get(id);
        if (previous != null) {
            throw new RuntimeException("id冲突:" + id);
        }
        wrappers.put(id, wrapper);
        inventories.put(wrapper.getInventory(), wrapper);
    }

    public void unregister(int id) {
        wrappers.remove(id);
    }
}
